home *** CD-ROM | disk | FTP | other *** search
- /*
- ** SRCHFILE.C - Functions for searching files
- **
- ** public domain by Bob Stout
- **
- ** Note: Although this snippet demonstrates some useful techniques, even
- ** the fast text searching algorithm used can't provide particularly
- ** good performance. Left as an exercise for the user is to perform
- ** explicit buffering using fread() rather than fgets() as is used
- ** here. See CHBYTES.C in SNIPPETS for how to perform searches in
- ** user-managed buffers.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define SUCCESS 0
-
- /*
- ** Allocate a big buffer, use it to buffer a specified stream
- */
-
- static size_t fsetup(FILE *fp, size_t minbuf)
- {
- register size_t bufsize;
- register char *buffer;
-
- /* Allocate the largest buffer we can */
-
- for (bufsize = 0x4000; bufsize >= minbuf; bufsize >>= 1)
- {
- if (NULL != (buffer = (char *) malloc(bufsize)))
- break;
- }
- if (NULL == buffer)
- return 0;
-
- /* Use the buffer to buffer the file */
-
- if (SUCCESS == setvbuf(fp, buffer, _IOFBF, bufsize))
- return bufsize;
- else return 0;
- }
-
- /*
- ** Search a file for a pattern match (forward)
- **
- ** Arguments: FILE pointer
- ** pattern to search for
- ** size of pattern
- ** find Nth occurance
- **
- ** Returns: -1L if pattern not found
- ** -2L in case of error
- */
-
- long ffsearch(FILE *fp, const char *pattern, const size_t size, int N)
- {
- long pos = -2L, tempos = 0L;
- char *sbuf, *p;
- size_t i, skip;
- int ch = 0;
-
- /* Allocate a search buffer */
-
- if (NULL == (sbuf = (char *)malloc(size - 1)))
- goto FDONE;
-
- /* Buffer the file and position us within it */
-
- if (0 == fsetup(fp, size))
- goto FDONE;
- pos = -1L;
- fseek(fp, 0L, SEEK_SET);
-
- /* Set up for smart searching */
-
- if (1 < strlen(pattern) && NULL != (p = strchr(pattern + 1, *pattern)))
- skip = p - (char *)pattern;
- else skip = strlen(pattern);
-
- /* Look for the pattern */
-
- while (EOF != ch)
- {
- if (EOF == (ch = fgetc(fp)))
- break;
- if ((int)*pattern == ch)
- {
- tempos = ftell(fp);
- if (size - 1 > fread(sbuf, sizeof(char), size - 1, fp))
- goto FDONE;
- if (SUCCESS == memcmp(sbuf, &pattern[1], size - 1))
- {
- if (0 == --N)
- {
- pos = tempos - 1L;
- goto FDONE;
- }
- }
- fseek(fp, tempos + skip, SEEK_SET);
- }
- }
-
- /* Clean up and leave */
-
- FDONE:
- free(sbuf);
- return pos;
- }
-
- /*
- ** Search a file for a pattern match (backwards)
- **
- ** Arguments: FILE pointer
- ** pattern to search for
- ** size of pattern
- ** find Nth occurance
- **
- ** Returns: -1L if pattern not found
- ** -2L in case of error
- */
-
- long rfsearch(FILE *fp, const char *pattern, const size_t size, int N)
- {
- long pos = -2L, tempos;
- char *sbuf, *p;
- size_t i, skip;
- int ch = 0;
-
- /* Allocate a search buffer */
-
- if (NULL == (sbuf = (char *)malloc(size - 1)))
- goto RDONE;
-
- /* Buffer the file and position us within it */
-
- if (0 == fsetup(fp, size))
- goto RDONE;
- pos = -1L;
- fseek(fp, -1L, SEEK_END);
- tempos = ftell(fp) - strlen(pattern);
-
- /* Set up for smart searching */
-
- if (1 < strlen(pattern) && NULL != (p = strrchr(pattern + 1, *pattern)))
- skip = strlen(pattern) - (p - (char *)pattern);
- else skip = strlen(pattern);
-
- /* Look for the pattern */
-
- while (0L <= tempos)
- {
- fseek(fp, tempos, SEEK_SET);
- if (EOF == (ch = fgetc(fp)))
- break;
- if ((int)*pattern == ch)
- {
- if (size - 1 <= fread(sbuf, sizeof(char), size - 1, fp))
- {
- if (SUCCESS == memcmp(sbuf, &pattern[1], size - 1))
- {
- if (0 == --N)
- {
- pos = tempos;
- goto RDONE;
- }
- }
- }
- tempos -= skip;
- }
- else --tempos;
- }
-
- /* Clean up and leave */
-
- RDONE:
- free(sbuf);
- return pos;
- }
-
- #ifdef TEST
-
- int main(int argc, char *argv[])
- {
- long pos;
- int N = 1;
- size_t size = strlen(argv[1]);
- char buf[256], *fname = "SRCHFILE.C";
- FILE *fp;
-
- if (2 > argc)
- {
- puts("Usage: SRCHFILE string [N] [file]");
- puts("where: N = find Nth occurance");
- puts(" If file is specified, N must be given");
- return EXIT_FAILURE;
- }
-
- if (2 < argc)
- N = atoi(argv[2]);
-
- if (3 < argc)
- fname = strupr(argv[3]);
-
- fp = fopen(fname, "r");
- printf("ffsearch(%s, %s) returned %ld\n", fname, argv[1],
- pos = ffsearch(fp, argv[1], size, N));
- fseek(fp, pos, SEEK_SET);
- fgets(buf, 256, fp);
- printf("...which contains \"%s\"\n\n", buf);
- fclose(fp);
-
- fp = fopen(fname, "rb");
- printf("rfsearch(%s, %s) returned %ld\n", fname, argv[1],
- pos = rfsearch(fp, argv[1], size, N));
- fseek(fp, pos, SEEK_SET);
- fgets(buf, 256, fp);
- printf("...which contains \"%s\"\n\n", buf);
- fclose(fp);
- return EXIT_SUCCESS;
- }
-
- #endif /* TEST */
-